package com.hulk.dryad.web.filter;

import com.hulk.dryad.common.constant.enums.BEC;
import com.hulk.dryad.common.exception.SecurityRteException;
import com.hulk.dryad.common.util.JacksonUtil;
import com.hulk.dryad.common.util.SignUtil;
import com.hulk.dryad.manage.provider.cache.SignKeyCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;


/**
 * Request包装类
 * <p>
 * 1.JSON签名check
 * 2.拓展requestbody无限获取(HttpServletRequestWrapper只能获取一次)
 * </p>
 *
 * @author hulk
 */
@Slf4j
public class SignatureServletRequestWrapper extends HttpServletRequestWrapper {

	/**
	 * 没被包装过的HttpServletRequest（特殊场景,需要自己过滤）
	 */
	HttpServletRequest orgRequest;

	SignKeyCache signKeyCache;

	Map attachMap;


	public SignatureServletRequestWrapper(HttpServletRequest request,SignKeyCache signKeyCache,Map param) {
		super(request);
		this.orgRequest = request;
		this.signKeyCache = signKeyCache;
		this.attachMap = param;
	}

	@Override
	public BufferedReader getReader() throws IOException {
		return new BufferedReader(new InputStreamReader(getInputStream()));
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		if (null == super.getHeader(HttpHeaders.CONTENT_TYPE)) {
			return super.getInputStream();
		}

		if (super.getHeader(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
			return super.getInputStream();
		}

		// 为空，直接返回
		String plainText = StreamUtils.copyToString(super.getInputStream(), StandardCharsets.UTF_8);
		if (!StringUtils.hasText(plainText))
		{
			return super.getInputStream();
		}
		Map jsonMap = JacksonUtil.readValue(plainText,Map.class);
		jsonMap.putAll(attachMap);
		check(jsonMap);
		final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(plainText.getBytes(StandardCharsets.UTF_8));

		return new ServletInputStream() {

			@Override
			public int read() {
				return byteArrayInputStream.read();
			}

			@Override
			public boolean isFinished() {
				return false;
			}

			@Override
			public boolean isReady() {
				return false;
			}

			@Override
			public void setReadListener(ReadListener readListener) {
			}
		};
	}



	/**
	 * 验证签名和防止重放攻击
	 * @param param
	 */
	protected void check(Map param ) {
		String key = signKeyCache.getSignKey();
		String signature = String.valueOf(param.get(SignUtil.SIGNATURE));
		boolean sflag = SignUtil.verify(param, signature,key);
		if (!sflag) {
			throw new SecurityRteException(BEC.E_2005);
		}


	}

}